local t = {creatures={}}
local t4Boss = Class({['isMember?']=true})
local t4Player = Class({['isMember?']=true})

t.events = {
    MapHookEvent.OnPlayerPendingEnter,
    MapHookEvent.OnPlayerLeaveMap,
    MapHookEvent.OnPlayerEnter,
    MapHookEvent.OnSendMessage,
}

t4Boss.events = {
    ObjectHookEvent.OnUnitHurted,
    ObjectHookEvent.OnUnitDead,
}

t4Player.events = {
    ObjectHookEvent.OnPlayerChangeTeam,
}

function main(pMapInstance, pHook)
    t.instance, t.hook = pMapInstance, pHook
    t.handler = pMapInstance:AttachMapHookInfo(t)
    t.vars = pHook:GetVariables()
    t.vars.DeployBoss = t.DeployBoss
    t.vars.Play = t.Play
end

function t.DeployBoss(entry, pos, args, lossHPVal)
    local pCreature = t.instance:CreateCustomCreature(entry, pos, args)
    pCreature:SubHPValue(lossHPVal)
    pCreature:GetAttribute():ModAttrEx(ATTREXTYPE.CANT_DEAD, 1)
    pCreature:AttachObjectHookInfo(t4Boss:new({boss=pCreature}))
    t.creatures[pCreature:GetSpawnId()] = pCreature
end

function t.Play(startTime, actvtTime)
    t.startTime, t.actvtTime = startTime, actvtTime
    t.timer = CreateHandlerTimer(t.hook,
        function() t.BroadcastRank() end, 3000)
    t.SyncBoss()
end

function t.SyncMember()
    local buffer = StringBuilder:new()
    buffer:WriteUInt64(t.instance:getInstGuid())
    buffer:WriteInt32(PBST_SyncMember)
    buffer:WriteUInt32(t.instance:GetMostPossiblePlayerCount())
    t.hook:SendPacket2Master(CMC_PLAYBOSS_SYNC, buffer:tostr())
end

function t.SyncBoss()
    local buffer = StringBuilder:new()
    buffer:WriteUInt64(t.instance:getInstGuid())
    buffer:WriteInt32(PBST_SyncBoss)
    for spawnId, pCreature in pairs(t.creatures) do
        buffer:WriteUInt32(spawnId)
        buffer:WriteUInt64(pCreature:GetS64Value(UNIT64_FIELD_HP_MAX))
    end
    t.hook:SendPacket2Master(CMC_PLAYBOSS_SYNC, buffer:tostr())
end

function t.BroadcastRank()
    local buffer = StringBuilder:new()
    t.instance:ForeachAllPlayer(function(playerGuid, pPlayer)
        buffer:WriteUInt64(playerGuid)
        buffer:append(pPlayer:PackClientAddr4Cross())
    end)
    t.hook:SendPacket2Master(CMC_PLAYBOSS_BROADCAST, buffer:tostr())
end

function t.OneRank(pPlayer)
    local buffer = StringBuilder:new()
    buffer:WriteUInt64(pPlayer:GetGuid())
    buffer:append(pPlayer:PackClientAddr4Cross())
    t.hook:SendPacket2Master(CMC_PLAYBOSS_BROADCAST, buffer:tostr())
end

function t.ChangeTeam(pPlayer)
    local buffer = StringBuilder:new()
    buffer:WriteUInt64(pPlayer:GetGuid())
    buffer:append(pPlayer:PackClientAddr4Cross())
    buffer:WriteUInt32(pPlayer:GetTeamId())
    buffer:WriteString(pPlayer:GetTeamName())
    t.hook:SendPacket2Master(CMC_PLAYBOSS_CHANGE_TEAM, buffer:tostr())
end

function t.OnPlayerPendingEnter(playerGuid)
    t.SyncMember()
end

function t.OnPlayerLeaveMap(playerGuid)
    t.SyncMember()
end

function t.OnPlayerEnter(pPlayer)
    local vars = pPlayer:GetVariables()
    if not vars['play.boss?'] then
        vars['play.boss?'] = pPlayer:AttachObjectHookInfo(t4Player:new({player=pPlayer}))
    end
    t.OneRank(pPlayer)
end

function t.OnPlayerStrike(args, instGuid, playerGuid, playerName, spawnId, loseHP)
    local pCreature = t.creatures[spawnId]
    if pCreature then
        pCreature:LoseHP(loseHP)
    end
end

function t.OnBossDead(args, playerGuid, playerName, spawnId)
    local pCreature = t.creatures[spawnId]
    if pCreature then
        pCreature:GetAttribute():ModAttrEx(ATTREXTYPE.CANT_DEAD, -1)
        pCreature:LoseHP(pCreature:GetS64Value(UNIT64_FIELD_HP))
    end
end

function t.OnActvtStop(arg, isSucc)
    RemoveTimer(t.hook, t.timer)
    pMapInstance:DetachMapHookInfo(t.handler)
end

function t4Boss:OnUnitHurted(pHurter, hurtValue)
    local buffer = StringBuilder:new()
    buffer:WriteUInt64(t.instance:getInstGuid())
    buffer:WriteUInt32(self.boss:GetSpawnId())
    buffer:WriteUInt64(hurtValue)
    local pPlayer = pHurter:GetPlayerOwner()
    buffer:WriteBool(pPlayer)
    if pPlayer then
        buffer:append(pPlayer:PackClientAddr4Cross())
        buffer:WriteUInt64(pPlayer:GetGuid())
        buffer:WriteString(pPlayer:GetName())
        buffer:WriteUInt32(pPlayer:GetTeamId())
        buffer:WriteString(pPlayer:GetTeamName())
    end
    t.hook:SendPacket2Master(CMC_PLAYBOSS_STRIKE, buffer:tostr())
end

function t4Boss:OnUnitDead(pKiller)
    t.creatures[self.boss:GetSpawnId()] = nil
end

function t4Player:OnPlayerChangeTeam(teamId)
    t.ChangeTeam(self.player)
end